<template>
	<input
			v-if="wrap==='input'"
			ref="real"
			class="bear-InputPowerful"
			:style="{textAlign:align}"
			:value="showValue"
			v-bind="$attrs"
			@input.passive="$_bear_inputFn"
			@focus.passive="$_bear_focusFn"
			@blur.passive="$_bear_blurFn"
			@change="$_bear_changeFn"
			v-on="listeners"/>
	<component
			v-else
			:is="wrap"
			ref="real"
			class="bear-InputPowerful"
			:style="{textAlign:align}"
			:value="showValue"
			v-bind="$attrs"
			@input.passive="$_bear_inputFn"
			@focus.passive="$_bear_focusFn"
			@blur.passive="$_bear_blurFn"
			@change="$_bear_changeFn"
			v-on="listeners"/>
</template>

<script>
	/* global utils */
	/**
	 * @author 唐国雄
	 * 带校验,格式化显示的输入框
	 * 属性----------------------
	 * v-model		输入框的实际值
	 * :validator	验证器
	 * :formatter	格式化器
	 * :required	是否必填
	 * :wrap		实际应用的元素标签,默认值: 'input'
	 * :align		对齐模式
	 * 方法----------------------
	 * format()			格式化当前输入框
	 * validate(init)	校验当前输入框
	 * autoHeight()		手动重新计算高度(只针对wrap为'TextareaAutoHeight')
	 * updateMaxWidth(width)	调整提示框宽度为指定宽度或元素宽度的2倍
	 */
	export default{
		name:'InputPowerful',
		inheritAttrs:false,
		props:{
			value:[String,Number],
			/**
			 * 验证器,只在值不为空时调用
			 * @param {String} val 输入框当前值
			 * @return {String|Boolean} 校验的失败的错误信息,或者校验的状态
			 */
			validator:Function,
			/**
			 * 格式化器,只在校验成功后调用(可能为空)
			 * @param {String} val 输入框当前值
			 * @return {String} 格式化以后的值
			 */
			formatter:Function,
			// 是否必填,或者指定没有值时的错误信息
			required:[Boolean,String],
			wrap:{
				type:String,
				default:'input'
			},
			align:String
		},
		data(){
			return {
				focus:false,
				errMsg:'',
				realValue:this.value,
				lastValue:this.value,
				showValue:''
			};
		},
		computed:{
			listeners(){
				const listeners=Object.assign({},this.$listeners);
				delete listeners.input;
				delete listeners.change;
				return listeners;
			}
		},
		watch:{
			value(val){
				this.realValue=val;
			},
			realValue(val){
				if(this.focus){
					this.showValue=val;
					this.debouncedValidate();
				}else{
					this.validate();
					this.format();
				}
			},
			errMsg(val){
				if(val){
					this.tipInstance.setContent(val);
					this.tipInstance.show();
				}else{
					this.tipInstance.hide();
				}
			}
		},
		created(){
			this.validate(true);
			this.format();
			if(this.errMsg){
				this.lastValue='';
			}
			this.debouncedValidate=utils.debounced(this.validate,130,this);
		},
		mounted(){
			this.tipInstance=utils.tippy(this.$el,{
				trigger:'manual',
				animation:'scale',
				hideOnClick:false,
				ignoreAttributes:true,
				maxWidth:this.$el.clientWidth*2
			});
		},
		beforeDestroy(){
			this.tipInstance.destroy();
		},
		methods:{
			$_bear_inputFn(e){
				const val=e.target?e.target.value:e;
				this.realValue=val;
				this.$emit('input',val);
			},
			$_bear_focusFn(){
				this.focus=true;
				this.showValue=this.realValue;
			},
			$_bear_blurFn(){
				this.focus=false;
				setTimeout(() => {
					this.format();
				},130);
			},
			$_bear_changeFn(){
				setTimeout(() => {
					if(this.errMsg){
						this.realValue=this.lastValue;
						this.$emit('input',this.lastValue);
					}else{
						this.lastValue=this.realValue;
						this.$emit('change');
					}
				},130);
			},
			/**
			 * 格式化当前输入框
			 */
			format(){
				if(this.formatter&&!this.errMsg){
					this.showValue=this.formatter(this.realValue);
				}else{
					this.showValue=this.realValue;
				}
			},
			/**
			 * 校验当前输入框
			 * @param {Boolean} [init] 是否忽略必填
			 * @return {Boolean} 校验状态
			 */
			validate(init){
				const required=this.required;
				const value=this.realValue;
				if(!init&&required&&!value){
					this.errMsg=typeof required==='string'?required:'此字段必填!';
					return false;
				}
				if(this.validator){
					if(value){
						const state=this.validator(value);
						if(state!==true){
							this.errMsg=state||'校验失败!';
							return false;
						}
					}
					this.errMsg='';
					return true;
				}
			},
			/**
			 * 手动重新计算高度(只针对wrap为'TextareaAutoHeight')
			 */
			autoHeight(){
				const real=this.$refs.real;
				if(real.autoHeight){
					real.autoHeight();
				}
			},
			/**
			 * 调整提示框宽度为指定宽度或元素宽度的2倍
			 * @param {Number} [width] 指定宽度
			 */
			updateMaxWidth(width){
				this.tipInstance.setProps({
					maxWidth:width||this.$el.clientWidth*2
				});
			}
		}
	};
</script>

<style lang="scss">
</style>
